package com.itcast.activiti.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itcast.activiti.domain.AllowUserObj;
import com.itcast.activiti.domain.ApproveNode;
import com.itcast.activiti.domain.UserInfo;
import com.itcast.activiti.entity.ApproveDefinition;
import com.itcast.activiti.service.ApproveJsonService;
import com.itcast.activiti.service.IActIdUserService;
import com.itcast.activiti.utils.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 审批组表  服务实现类
 * </p>
 */
@Service
public class ApproveJsonServiceImpl implements ApproveJsonService {

    private static ApproveNode END_APPROVE_NODE = new ApproveNode();
    @Autowired
    private IActIdUserService iActIdUserService;

    @Override
    public String allowUserJsonStrToList(List<AllowUserObj> allowUserObjs) {
        if (allowUserObjs == null) allowUserObjs = new ArrayList<>();
        for (AllowUserObj allowUserObj : allowUserObjs) {
            // 类型为部门ID
            if ("1".equals(allowUserObj.getObjectType())) {
                allowUserObj.setObjectName(iActIdUserService.getDepartmentById(allowUserObj.getObjectId()).getName());
            } else if ("2".equals(allowUserObj.getObjectType())) {
                allowUserObj.setObjectName(iActIdUserService.getUserNameById(allowUserObj.getObjectId()));
            } else {
                throw new RuntimeException("节点用户的处理人类型错误！" + allowUserObj.getObjectType());
            }
        }
        return JSONObject.toJSONString(allowUserObjs);
    }

    @Override
    public String parseFlowJson(JSONArray flowData) {
        try {
            JSONArray jsonArray = JSONObject.parseArray(flowData.toJSONString());
            if (jsonArray == null || jsonArray.size() == 0) throw new RuntimeException("解析流程json为空！");
            for (int i = 0; i < jsonArray.size(); i++) {
                parseFlowNode((JSONObject) jsonArray.get(i));
            }
            return jsonArray.toJSONString();
        } catch (Exception e) {
            throw new RuntimeException("解析流程json出错！" + e.getMessage());
        }
    }

    // 解析 流程json 获取 节点列表
    @Override
    public List<ApproveNode> getApproveNodesFromJson(ApproveDefinition approveDefinition, String startUserId, boolean satisfy) {
        JSONArray jsonArray = JSONObject.parseArray(approveDefinition.getFlowJson());
        if (jsonArray == null || jsonArray.size() == 0) throw new RuntimeException("解析流程json为空！");
        if (!"start".equals(((JSONObject) jsonArray.get(0)).getString("type")))
            throw new RuntimeException("解析流程json出错！第一个节点不是start节点！");
        if (!"end".equals(((JSONObject) jsonArray.get(jsonArray.size() - 1)).getString("type")))
            throw new RuntimeException("解析流程json出错！最后一个节点不是end节点！");
        // 生成的列表
        List<ApproveNode> approveNodes = new ArrayList<>();
        // 计算生成的列表
        flowNodeArrayToActiviti(approveDefinition, approveNodes, jsonArray, startUserId, satisfy);
        if (approveNodes.size() < 2) throw new RuntimeException("计算应执行节点类别出错！");
        // 如果节点列表中包含 END_APPROVE_NODE，说明获取到的节点路径能执行到底
        if (approveNodes.contains(END_APPROVE_NODE)) {
            approveNodes.remove(END_APPROVE_NODE);
        }
        // 如果节点列表中不包含 END_APPROVE_NODE，说明获取到的节点路径不能执行到底，可能是由于json内容问题 或者 分支条件问题引起
        else {
            throw new RuntimeException("无法获取到能够执行结束的执行路径，请检查条件分支相关内容！");
        }
        // 计算 nextNodeId
        for (int i = 0; i < approveNodes.size() - 1; i++) {
            approveNodes.get(i).setNextNodeKey(approveNodes.get(i + 1).getNodeKey());
        }
        // 对节点列表重排序
        approveNodes = reSortApproveNodes(approveNodes);
        return approveNodes;
    }

    // 解析 流程json 中的某一个节点，获取这个节点的应处理人
    @Override
    public List<UserInfo> getNodeOughtUsers(JSONObject curr, String startUserId) {
        String userType = curr.getString("userType");
        String mangerLevel = curr.getString("mangerLevel");
        JSONArray userRange = curr.getJSONArray("userRange");
        // 当前用户
        UserInfo currUser = iActIdUserService.getUserById(startUserId);
        // 节点成员列表
        List<UserInfo> oughtUsers = new ArrayList<>();
        if (!StringUtils.hasText(userType)) {
            return oughtUsers;
        }
        // 审批指定成员、只会指定成员
        if (Arrays.asList("1", "5", "6").contains(userType)) {
            if (userRange != null && userRange.size() > 0) {
                for (int i = 0; i < userRange.size(); i++) {
                    JSONObject one = (JSONObject) userRange.get(i);
                    String objectId = one.getString("objectId");
                    String objectType = one.getString("objectType");
                    // 类型为部门ID
                    if ("1".equals(objectType)) {
                        List<UserInfo> users = iActIdUserService.getUsersByDepartmentId(objectId);
                        for (UserInfo user : users) {
                            oughtUsers.add(user);
                        }
                        // 用户
                    } else if ("2".equals(objectType)) {
                        UserInfo user = iActIdUserService.getUserById(objectId);
                        oughtUsers.add(user);
                        // 自定义用户
                    } else if ("3".equals(objectType)) {
                        List<UserInfo> users = iActIdUserService.getUsersByActIdProcessId(objectId, startUserId);
                        for (UserInfo user : users) {
                            oughtUsers.add(user);
                        }
                    } else {
                        throw new RuntimeException("节点用户的处理人类型错误！" + objectType);
                    }
                }
            }

        }
        // 审批主管
        else if ("2".equals(userType)) {
            // 直接主管
            if ("1".equals(mangerLevel)) {
                String departmentId = iActIdUserService.getDepartmentIdByUserId(currUser.getUserId());
                if (StringUtils.isEmpty(departmentId)) throw new RuntimeException("依据当前用户获取部门出错！");
                UserInfo user = iActIdUserService.getDepartmentManager(departmentId);
                if (user == null) throw new RuntimeException("获取部门负责人出错！" + departmentId);
                oughtUsers.add(user);
            }
            // 二级主管
            else if ("2".equals(mangerLevel)) {
                String departmentId = iActIdUserService.getDepartmentIdByUserId(currUser.getUserId());
                if (StringUtils.isEmpty(departmentId)) throw new RuntimeException("依据当前用户获取部门出错！");
                String parentDepartmentId = iActIdUserService.getParentDepartmentIdById(departmentId);
                if (StringUtils.isEmpty(parentDepartmentId)) throw new RuntimeException("依据当前用户获取二级部门出错！");
                UserInfo user = iActIdUserService.getDepartmentManager(parentDepartmentId);
                if (user == null) throw new RuntimeException("获取部门负责人出错！" + departmentId);
                oughtUsers.add(user);
            }
            // 三级主管
            else if ("3".equals(mangerLevel)) {
                String departmentId = iActIdUserService.getDepartmentIdByUserId(currUser.getUserId());
                if (StringUtils.isEmpty(departmentId)) throw new RuntimeException("依据当前用户获取部门出错！");
                String parentDepartmentId = iActIdUserService.getParentDepartmentIdById(departmentId);
                if (StringUtils.isEmpty(parentDepartmentId)) throw new RuntimeException("依据当前用户获取二级部门出错！");
                String grandDepartmentId = iActIdUserService.getParentDepartmentIdById(departmentId);
                if (StringUtils.isEmpty(grandDepartmentId)) throw new RuntimeException("依据当前用户获取三级部门出错！");
                UserInfo user = iActIdUserService.getDepartmentManager(grandDepartmentId);
                if (user == null) throw new RuntimeException("获取部门负责人出错！" + departmentId);
                oughtUsers.add(user);
            } else {
                throw new RuntimeException("主管类型错误！" + mangerLevel);
            }
        }
        // 发起人自选
        else if ("3".equals(userType)) {
            // 发起人自选先不实现，临时写死为当前用户
            oughtUsers.add(currUser);
        }
        // 发起人自己
        else if ("4".equals(userType)) {
            oughtUsers.add(currUser);
        }
        else if (!StringUtils.hasText(userType)) {
            oughtUsers.add(currUser);
        }
        return oughtUsers;
    }

    // 对节点列表重排序
    private List<ApproveNode> reSortApproveNodes(List<ApproveNode> approveNodeList) {
        List<ApproveNode> approveNodeListDesc = new ArrayList<>();
        List<ApproveNode> approveNodeListAsc = new ArrayList<>();
        ApproveNode endNode = null;
        // 寻找结束节点
        for (int i = 0; i < approveNodeList.size(); i++) {
            if (StringUtils.isEmpty(approveNodeList.get(i).getNextNodeKey())) {
                endNode = approveNodeList.get(i);
            }
        }
        // 指针，初始化指向结束节点
        ApproveNode point = endNode;
        while (point != null) {
            approveNodeListDesc.add(point);
            ApproveNode temp = null;
            for (int i = 0; i < approveNodeList.size(); i++) {
                if (point.getNodeKey().equals(approveNodeList.get(i).getNextNodeKey())) {
                    temp = approveNodeList.get(i);
                    break;
                }
            }
            point = temp;
        }
        // 至此，approveNodeListDesc 中节点按倒叙排序，将其反序重新添加回 approveNodeListAsc 中
        for (int i = approveNodeListDesc.size() - 1; i >= 0; i--)
            approveNodeListAsc.add(approveNodeListDesc.get(i));
        // 重排序后校验
        if (approveNodeListAsc.size() != approveNodeList.size()) throw new RuntimeException("审批节点重排序失败，排序前后节点数量不一致！");
        return approveNodeListAsc;
    }

    // 中间节点，只有 CCList、approval、condition 三种类型
    private void flowNodeArrayToActiviti(ApproveDefinition approveDefinition, List<ApproveNode> approveNodes, JSONArray arr, String startUserId, boolean satisfy) {
        for (int i = 0; i < arr.size(); i++) {
            JSONObject curr = (JSONObject) arr.get(i);
            flowNodeObjectToActiviti(approveDefinition, approveNodes, curr, startUserId, satisfy);
        }
    }

    // 将自定义的JSON对象转为 ApproveNode 对象格式。satisfy： true获取满足条件的路径节点；false获取所有的路径节点
    private void flowNodeObjectToActiviti(ApproveDefinition approveDefinition, List<ApproveNode> approveNodes, JSONObject curr, String startUserId, boolean satisfy) {
        if ("condition".equals(curr.getString("type"))) {
            JSONArray branchs = (JSONArray) curr.get("node");
            if (branchs == null || branchs.size() == 0)
                throw new RuntimeException("未获取到条件判断下的具体分支：" + curr.getString("id"));
            // 循环遍历 branchs
            for (int i = 0; i < branchs.size(); i++) {
                JSONArray conds = (JSONArray) branchs.get(i);
                if (conds == null || conds.size() < 1)
                    throw new RuntimeException("未获取到条件判断下的具体分支：" + curr.getString("id"));
                // 没有满足条件的要求限制，所有的路径都取
                flowNodeArrayToActiviti(approveDefinition, approveNodes, conds, startUserId, satisfy);
            }
        } else if (Arrays.asList("CCList", "approval").contains(curr.getString("type"))) {
            ApproveNode approveNode = new ApproveNode();
            approveNode.setDefinitionId(approveDefinition.getId());
            approveNode.setNodeKey(curr.getString("nodeKey"));
            approveNode.setNextNodeKey(null); // 设置为null，列表出来之后再统一设置
            approveNode.setName(curr.getString("name"));
            // 计算 应处理人用户
            approveNode.setOughtUsers(getNodeOughtUsers(curr, startUserId));
            approveNodes.add(approveNode);
        }
        // 开始节点
        else if (Arrays.asList("start").contains(curr.getString("type"))) {
            ApproveNode approveNode = new ApproveNode();
            approveNode.setDefinitionId(approveDefinition.getId());
            approveNode.setNodeKey(curr.getString("nodeKey"));
            approveNode.setName(curr.getString("name"));
            approveNode.setNextNodeKey(null); // 设置为null，列表出来之后再统一设置
            approveNode.setOughtUsers(getNodeOughtUsers(curr, startUserId));
            approveNodes.add(approveNode);
        }
        // 结束节点
        else if (Arrays.asList("end").contains(curr.getString("type"))) {
            // 加入结束节点
            approveNodes.add(END_APPROVE_NODE);
        }
        // 条件节点，不做任何处理
        else if (Arrays.asList("cond").contains(curr.getString("type"))) {
        } else {
            throw new RuntimeException("解析根节点下节点类型出错：" + curr.getString("type"));
        }
    }

    private void parseFlowNode(JSONObject node) {
        String type = node.getString("type");
        String id = node.getString("id");
        if (StringUtils.isEmpty(id)) {
            id = UUIDUtils.randomUuid();
            node.put("id", id);
        }
        String nodeKey = node.getString("nodeKey");
        if (StringUtils.isEmpty(nodeKey)) {
            nodeKey = UUIDUtils.randomUuid();
            node.put("nodeKey", nodeKey);
        }
        if ("start".equals(type)) {

        } else if ("condition".equals(type)) {
            JSONArray conds = (JSONArray) node.get("node");
            if (conds == null || conds.size() == 0) throw new RuntimeException("未获取到条件判断下的具体分支：" + id);

            for (int i = 0; i < conds.size(); i++) {
                JSONArray branchs = (JSONArray) conds.get(i);
                for (int j = 0; j < branchs.size(); j++) {
                    if (j == 0) {
                        if (!"cond".equals(((JSONObject) branchs.get(j)).getString("type")))
                            throw new RuntimeException("条件节点下分支中第一个节点不是cond类型！" + id);
                    } else {
                        if (!Arrays.asList("CCList", "approval", "condition").contains(((JSONObject) branchs.get(j)).getString("type")))
                            throw new RuntimeException("条件节点下分支中非第一个节点不是只会类型、审批类型、条件类型之一！" + id);
                    }
                    parseFlowNode((JSONObject) branchs.get(j));
                }
            }
        } else if ("cond".equals(type)) {
            String conditionExpression = node.getString("conditionExpression");
            if (StringUtils.isEmpty(conditionExpression)) throw new RuntimeException("条件分支的条件表达式为空！：" + id);
        } else if ("CCList".equals(type)) {
        } else if ("approval".equals(type)) {
        }
    }
}
